package com.learn.javase.chapter18.classloader;

import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;

/**
 * @author wsh
 * @date 2022-05-10 09:02
 */
public class ShowClassLoader {
    /**
     * 查看类加载器类型
     *
     * @author wsh
     * @date 2022/5/10
     */
    private void printClassLoaderType() {
        System.out.println("========== 打印类加载器类型 Begin ==========");
        //系统类加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println("系统类加载器：" + systemClassLoader);//系统类加载器：sun.misc.Launcher$AppClassLoader@4e0e2f2a
        //扩展类加载器
        ClassLoader extClassLoader = systemClassLoader.getParent();
        System.out.println("扩展类加载器：" + extClassLoader);//扩展类加载器：sun.misc.Launcher$ExtClassLoader@2a139a55
        //根类加载器。因实现语言是C++，自然不是Java对象，也不可能继承java.lang.ClassLoader，所以返回null。
        ClassLoader bootstrapClassLoader = extClassLoader.getParent();
        System.out.println("根类加载器：" + bootstrapClassLoader);//根类加载器：null
        //自定义类加载器
        ClassLoader customClassLoader = this.getClass().getClassLoader();
        System.out.println("自定义类加载器：" + customClassLoader);//自定义类加载器：sun.misc.Launcher$AppClassLoader@4e0e2f2a
        System.out.println("========== 打印类加载器类型 End ==========");
    }

    /**
     * 系统内置类，是根类加载器
     *
     * @author wsh
     * @date 2022/5/10
     */
    private void printSystemClassType() {
        System.out.println("========== 打印系统内置类的类加载器类型 Begin ==========");
        //系统内置类。以系统内置类Object为例
        ClassLoader classLoader = Object.class.getClassLoader();
        System.out.println("系统内置类的类加载器类型：" + classLoader);//系统内置类的类加载器类型：null
        System.out.println("========== 打印系统内置类的类加载器类型 End ==========");
    }

    /**
     * 查看根类加载器加载的类库
     * 使用了Launcher，但不够安全。
     *
     * @author wsh
     * @date 2022/5/10
     */
    private void showBootstrapClassLoaderJar() {
        System.out.println("========== 查看根类加载器加载的类库 Begin ==========");
        /**
         * TODO 首次运行时控制台会收到警告（内部专用API，可能会在未来发行版中删除）。无须理会，再次运行即可。
         * 根类加载器，返回null。所以改用这种方式获取。
         */
//        URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
//        for (int i = 0; i < urls.length; i++) {
//            System.out.println(urls[i].toExternalForm());
//        }
        //打印的结果如下：
        //file:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/resources.jar
        //file:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/rt.jar
        //file:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/sunrsasign.jar
        //file:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/jsse.jar
        //file:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/jce.jar
        //file:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/charsets.jar
        //file:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/jfr.jar
        //file:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/classes
        System.out.println("========== 查看根类加载器加载的类库 End ==========");
    }

    /**
     * 查看根类加载器加载的类库
     * 先取系统类加载器 -> 扩展类加载器 -> 根类加载器，再查看其下类库，但根类加载器是null，此路不通。
     *
     * @author wsh
     * @date 2022/5/10
     */
    private void showBootstrapClassLoaderJar2() throws IOException {
        System.out.println("========== 查看根类加载器加载的类库2 Begin ==========");
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        ClassLoader extClassLoader = systemClassLoader.getParent();
        ClassLoader bootstrapClassLoader = extClassLoader.getParent();//null
        String bootstrapClassLoaderPath = System.getProperty("sun.boot.library.path");
        System.out.println("根类加载器，类库路径：" + bootstrapClassLoaderPath);///Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib

        //上面返回null，这里肯定执行不了
        /*Enumeration<URL> bootstrapClassLoaderResources = bootstrapClassLoader.getResources(bootstrapClassLoaderPath);
        while (bootstrapClassLoaderResources.hasMoreElements()) {
            System.out.println("根类加载器，加载的类库：" + bootstrapClassLoaderResources.nextElement());
        }*/
        System.out.println("========== 查看根类加载器加载的类库2 End ==========");
    }

    /**
     * 查看扩展类加载器加载的类库
     *
     * @author wsh
     * @date 2022/5/10
     */
    private void showExtClassLoaderJar() throws IOException {
        System.out.println("========== 查看扩展类加载器加载的类库 Begin ==========");
        //系统类加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        //扩展类加载器
        ClassLoader extClassLoader = systemClassLoader.getParent();
        System.out.println("扩展类加载器：" + extClassLoader);
        String extClassLoaderPath = System.getProperty("java.ext.dirs");
        System.out.println("扩展类加载器，类库路径：" + extClassLoaderPath);
        ///Users/apple/Library/Java/Extensions:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/ext:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java

        String[] pathArray = extClassLoaderPath.split(":");
        if (pathArray != null && pathArray.length > 0) {
            for (int i = 0; i < pathArray.length; i++) {
                String path = pathArray[i];
                System.out.println("扩展类加载器，类库路径" + (i + 1) + "：" + path);
                //路径1：/Users/apple/Library/Java/Extensions
                //路径2：/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/ext
                //路径3：/Library/Java/Extensions
                //路径4：/Network/Library/Java/Extensions
                //路径5：/System/Library/Java/Extensions
                //路径6：/usr/lib/java

                //默认其下没有类库，也可能是我加载方式不对
                Enumeration<URL> lib = extClassLoader.getResources(path);
                while (lib.hasMoreElements()) {
                    System.out.println("扩展类加载器，加载的类库：" + lib.nextElement());
                }
            }
        }
        System.out.println("========== 查看扩展类加载器加载的类库 End ==========");
    }

    /**
     * 查看系统类加载器加载的类库
     *
     * @author wsh
     * @date 2022/5/10
     */
    private void showSystemClassLoaderJar() throws IOException {
        System.out.println("========== 查看系统类加载器加载的类库 Begin ==========");
        //系统类加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println("系统类加载器：" + systemClassLoader);
        /**
         * 获取系统类加载器的加载路径。
         * 通常由classpath环境变量指定，如果操作系统没有该该变量，则默认当前路径为系统类加载器的加载路径。
         */
        Enumeration<URL> libPathEnum = systemClassLoader.getResources("");
        while (libPathEnum.hasMoreElements()) {
            System.out.println("系统类加载器，类库路径：" + libPathEnum.nextElement());
        }
        //返回值如下：
        //路径1：file:/Users/apple/workspaces/idea/study/learn-javase/build/classes/java/main/
        //路径2：file:/Users/apple/workspaces/idea/study/learn-javase/build/resources/main/
        System.out.println("========== 查看系统类加载器加载的类库 End ==========");
    }

    public static void main(String[] args) throws Exception {
        ShowClassLoader showClassLoader = new ShowClassLoader();
        //查看类加载器类型
        //showClassLoader.printClassLoaderType();
        //系统内置类，是根类加载器
        //showClassLoader.printSystemClassType();
        //查看根类加载器所加载的核心类库
        //showClassLoader.showBootstrapClassLoaderJar();
        //showClassLoader.showBootstrapClassLoaderJar2();
        //查看扩展类加载器加载的类库
        //showClassLoader.showExtClassLoaderJar();
        //查看系统类加载器加载的类库
        //showClassLoader.showSystemClassLoaderJar();
    }
}
